package com.hyt.it.ogt.kq.service.gov.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.util.StringUtils;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.constant.StringCodeEnum;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.exception.GovInvalidRequestException;
import com.hyt.it.ogt.kq.common.gov.enums.CacheKeyEnum;
import com.hyt.it.ogt.kq.service.gov.feign.pt.GovPtClient;
import com.hyt.it.ogt.kq.service.gov.mapper.OfficeAreaMapper;
import com.hyt.it.ogt.kq.service.gov.model.dto.PtOfficeAreaDTO;
import com.hyt.it.ogt.kq.service.gov.model.entity.OfficeArea;
import com.hyt.it.ogt.kq.service.gov.model.entity.TaskArea;
import com.hyt.it.ogt.kq.service.gov.model.excel.AreaSheet;
import com.hyt.it.ogt.kq.service.gov.model.excel.listener.AreaListener;
import com.hyt.it.ogt.kq.service.gov.service.IOfficeAreaService;
import com.hyt.it.ogt.kq.common.gov.utils.TextUtil;
import org.apache.commons.io.FilenameUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 区域信息表 服务实现类
 * </p>
 *
 * @author huangyh
 * @since 2021-03-08
 */
@Service
public class OfficeAreaServiceImpl extends BaseServiceImpl<OfficeAreaMapper, OfficeArea> implements IOfficeAreaService {

    @Override
    public String getNameByAreaId(String officeId, String areaId) throws GovInvalidRequestException {
        String name = baseMapper.getNameByAreaId(officeId, areaId);
        if (StringUtils.isEmpty(name)) {
            //区域不存在
            throw new GovInvalidRequestException(ResponseCode.EXAM_AREA_NON_EXIST.getCode(), "区域不存在");
        }
        return name;
    }

    @Override
    public void initOfficeArea(String officeId) {
        Integer count = this.lambdaQuery()
                .eq(OfficeArea::getOfficeId,officeId)
                .eq(OfficeArea::getDelFlag,false)
                .count();
        if (count <= 0) {
            baseMapper.initOfficeArea(officeId);
        }
    }

    @Override
    public void removeOfficeArea() {
        this.lambdaUpdate()
                .set(OfficeArea::getDelFlag,true)
                .update();
    }

    @Override
    public void importOfficeArea(MultipartFile file, String officeId) throws KqException, IOException {
        //校验excel文件
        this.excelVerify(file);
        //校验机构是否存在机构考生区域数据
        this.checkOfficeAreaExist(officeId);
        //读取excel文件
        List<AreaSheet> areaSheetList = this.readExcel(file);
        //校验excel内容
        this.contentVerify(areaSheetList);
        //组装数据
        List<OfficeArea> officeAreaList = this.convertOfficeArea(areaSheetList, officeId);
        //保存机构考生区域数据
        this.saveOfficeCandidateArea(officeAreaList);
    }

    @Override
    public Map<String,OfficeArea> getOfficeAreaMap(String officeId) {
        List<OfficeArea> officeAreaList = this.lambdaQuery()
                .eq(OfficeArea::getOfficeId,officeId)
                .eq(OfficeArea::getDelFlag,false)
                .list();
        Map<String,OfficeArea> map = new HashMap<>(officeAreaList.size());
        officeAreaList.stream().forEach(officeArea -> {
            map.put(officeArea.getAreaId(),officeArea);
        });
        return map;
    }

    /**
     * 校验excel文件
     * @param file excel文件
     * @throws KqException 异常
     */
    private void excelVerify(MultipartFile file) throws KqException {
        if (file.isEmpty()) {
            //导入文件不存在
            throw new KqException(ResponseCode.IMPORT_FILE_NOT_EXIST.getCode(),
                    ResponseCode.IMPORT_FILE_NOT_EXIST.getMsg());
        }
        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            //导入文件类型错误
            throw new KqException(ResponseCode.WRONG_FILE_TYPE.getCode(),
                    ResponseCode.WRONG_FILE_TYPE.getMsg());
        }
        String ext = FilenameUtils.getExtension(fileName);
        if (!ext.equalsIgnoreCase(StringCodeEnum.EXCEL_XLS.getCode())
                && !ext.equalsIgnoreCase(StringCodeEnum.EXCEL_XLSX.getCode())) {
            //导入文件类型错误
            throw new KqException(ResponseCode.WRONG_FILE_TYPE.getCode(),ResponseCode.WRONG_FILE_TYPE.getMsg());
        }
    }

    /**
     * 校验机构是否存在机构区域数据
     * @param officeId 机构id
     * @throws KqException 异常
     */
    private void checkOfficeAreaExist(String officeId) throws KqException {
        Integer count = this.lambdaQuery()
                .eq(OfficeArea::getOfficeId, officeId)
                .eq(OfficeArea::getDelFlag, false)
                .count();
        if (count > 0) {
            //当前机构存在机构区域数据，无法导入
            throw new KqException(ResponseCode.HAS_OFFICE_CANDIDATE_AREA.getCode(),
                    ResponseCode.HAS_OFFICE_CANDIDATE_AREA.getMsg());
        }
    }

    /**
     * 读取excel文件
     * @param file excel文件
     * @return excel内容
     * @throws IOException IO异常
     */
    private List<AreaSheet> readExcel(MultipartFile file) throws IOException {
        AreaListener areaListener = new AreaListener();
        EasyExcel.read(file.getInputStream(), AreaSheet.class, areaListener)
                .sheet().doRead();
        return areaListener.getDataList();
    }

    /**
     * 校验excel内容
     * @param areaSheetList excel内容
     * @throws KqException 异常
     */
    private void contentVerify(List<AreaSheet> areaSheetList) throws KqException {
        if (CollectionUtils.isEmpty(areaSheetList)) {
            throw new KqException(ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getCode(),
                    ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getMsg());
        }
        for (int i = 0; i < areaSheetList.size(); i++) {
            AreaSheet area = areaSheetList.get(i);
            int rowNumber = i + 1;
            if (org.apache.commons.lang3.StringUtils.isEmpty(area.getCountryName())) {
                throw new KqException(ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getCode(), "第" + rowNumber + "行数据国名称为空");
            }
            if (!TextUtil.isLongNum(area.getCityCode())) {
                throw new KqException(ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getCode(), "第" + rowNumber + "行数据国编码格式不正确");
            }
            if (org.apache.commons.lang3.StringUtils.isEmpty(area.getProvinceName())) {
                throw new KqException(ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getCode(), "第" + rowNumber + "行数据省名称为空");
            }
            if (!TextUtil.isLongNum(area.getProvinceCode())) {
                throw new KqException(ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getCode(), "第" + rowNumber + "行数据省编码格式不正确");
            }
            // 完善各字段校验
        }

    }

    /**
     * 组装区域数据
     * @param areaSheetList excel内容
     * @return 组装结果
     */
    private List<OfficeArea> convertOfficeArea(List<AreaSheet> areaSheetList, String officeId) {
        //筛选国数据
        List<AreaSheet> countryList = areaSheetList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AreaSheet::getCountryCode))), ArrayList::new
                ));
        //筛选省数据
        List<AreaSheet> provinceList = areaSheetList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AreaSheet::getProvinceCode))), ArrayList::new
                ));
        //筛选市数据
        List<AreaSheet> cityList = areaSheetList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AreaSheet::getCityCode))), ArrayList::new
                ));
        //筛选区县数据
        List<AreaSheet> districtList = areaSheetList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AreaSheet::getDistrictCode))), ArrayList::new
                ));
        //组装国
        List<OfficeArea> officeAreaList = countryList.stream().map(country -> {
            OfficeArea officeArea = new OfficeArea();
            officeArea.setAreaId(country.getCountryCode())
                    .setName(country.getCountryName())
                    .setType("1")
                    .setOfficeId(officeId);
            return officeArea;
        }).collect(Collectors.toList());
        //组装省
        List<OfficeArea> provinceAreaList = provinceList.stream().map(province -> {
            OfficeArea officeArea = new OfficeArea();
            officeArea.setAreaId(province.getProvinceCode())
                    .setParentId(province.getCountryCode())
                    .setParentIds(province.getCountryCode())
                    .setName(province.getProvinceName())
                    .setType("2")
                    .setOfficeId(officeId);
            return officeArea;
        }).collect(Collectors.toList());
        officeAreaList.addAll(provinceAreaList);
        //组装市
        List<OfficeArea> cityAreaList = cityList.stream().map(city -> {
            OfficeArea officeArea = new OfficeArea();
            officeArea.setAreaId(city.getCityCode())
                    .setParentId(city.getProvinceCode())
                    .setParentIds(org.apache.commons.lang3.StringUtils.join(city.getCountryCode(), ",", city.getProvinceCode()))
                    .setName(city.getCityName())
                    .setType("3")
                    .setOfficeId(officeId);
            return officeArea;
        }).collect(Collectors.toList());
        officeAreaList.addAll(cityAreaList);
        //组装区县
        List<OfficeArea> districtAreaList = districtList.stream().map(district -> {
            OfficeArea officeArea = new OfficeArea();
            officeArea.setAreaId(district.getDistrictCode())
                    .setParentId(district.getCityCode())
                    .setParentIds(org.apache.commons.lang3.StringUtils.join(district.getCountryCode(), ",", district.getProvinceCode(), ",", district.getCityCode()))
                    .setName(district.getDistrictName())
                    .setType("4")
                    .setOfficeId(officeId);
            return officeArea;
        }).collect(Collectors.toList());
        officeAreaList.addAll(districtAreaList);
        return officeAreaList;
    }

    /**
     * 保存机构区域数据
     * @param officeAreaList 机构区域数据
     * @throws KqException 异常
     */
    private void saveOfficeCandidateArea(List<OfficeArea> officeAreaList) throws KqException {
        if (!saveBatch(officeAreaList)) {
            //插入机构区域表失败
            throw new KqException(ResponseCode.IMPORT_SYS_AREA_EXCEPTION.getCode(),
                    ResponseCode.IMPORT_SYS_AREA_EXCEPTION.getMsg());
        }
    }

    @Resource
    private GovPtClient govPtClient;
    @Resource
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 从平台查询区域
     * @return
     */
    @Override
    public List<TaskArea> getAllAreaList(){
        String key = CacheKeyEnum.GOV_OFFICE_AREA_CACHE_LIST_KEY.getCacheEnumKey("1");
        try {
            if(Boolean.TRUE.equals(redisTemplate.hasKey(key))){
                String listStr = redisTemplate.opsForValue().get(key);
                List<TaskArea> newList = JSONObject.parseObject(listStr,new TypeReference<List<TaskArea>>(){});
                return newList;
            }
            ApiResponse<List<PtOfficeAreaDTO>> allAreas = govPtClient.getAllAreas();
            if(!Objects.equals(ResponseCode.SUCCESS.getCode(),allAreas.getCode()) || Objects.isNull(allAreas.getData())){
                throw new KqException(ResponseCode.ERROR_PT_AREA.getCode(),ResponseCode.ERROR_PT_AREA.getMsg());
            }
            List<TaskArea> taskAreas = new ArrayList<>(allAreas.getData().size());
            for (PtOfficeAreaDTO dto : allAreas.getData()){
                TaskArea area = new TaskArea();
                area.setAreaId(dto.getId());
                area.setName(dto.getName());
                area.setFunction(0);
                area.setParentIds(dto.getParentIds());
                area.setParentId(String.valueOf(dto.getParentId()));
                area.setRegionLevel(dto.getRegionLevel());
                area.setType(String.valueOf(dto.getRegionLevel() + 1));
                area.setCode(String.valueOf(dto.getRegionCode()) + 1);
                area.setFullName(dto.getFullName());
                taskAreas.add(area);
            }
            //Map<String,TaskArea> map = taskAreas.stream().collect(Collectors.toMap(TaskArea::getAreaId, Function.identity(),(k1, k2) -> k1));
            return taskAreas;
        } catch (Exception e){
            log.error("从redis中取出机构区域信息异常",e);
            ApiResponse<List<PtOfficeAreaDTO>> allAreas = govPtClient.getAllAreas();
            if(!Objects.equals(ResponseCode.SUCCESS.getCode(),allAreas.getCode()) || Objects.isNull(allAreas.getData())){
                throw new KqException(ResponseCode.ERROR_PT_AREA.getCode(),ResponseCode.ERROR_PT_AREA.getMsg());
            }
            List<TaskArea> taskAreas = new ArrayList<>(allAreas.getData().size());
            for (PtOfficeAreaDTO dto : allAreas.getData()){
                TaskArea area = new TaskArea();
                area.setAreaId(dto.getId());
                area.setName(dto.getName());
                area.setFunction(0);
                area.setParentIds(dto.getParentIds());
                area.setParentId(String.valueOf(dto.getParentId()));
                area.setRegionLevel(dto.getRegionLevel());
                area.setType(String.valueOf(dto.getRegionLevel()) + 1);
                area.setCode(String.valueOf(dto.getRegionCode()) + 1);
                taskAreas.add(area);
            }
            //Map<String,TaskArea> map = taskAreas.stream().collect(Collectors.toMap(TaskArea::getAreaId, Function.identity(),(k1, k2) -> k1));
            return taskAreas;
        }
    }

    //获取平台的区域map key = id  value = object
    @Override
    public Map<String, TaskArea> getAllAreaMap(){
        String key = CacheKeyEnum.GOV_OFFICE_AREA_CACHE_MAP_KEY.getCacheEnumKey("1");
        try {
            if(Boolean.TRUE.equals(redisTemplate.hasKey(key))){
                String mapStr = redisTemplate.opsForValue().get(key);
                Map<String,TaskArea> newMap = JSONObject.parseObject(mapStr,new TypeReference<Map<String,TaskArea>>(){});
                return newMap;
            }
            ApiResponse<List<PtOfficeAreaDTO>> allAreas = govPtClient.getAllAreas();
            if(!Objects.equals(ResponseCode.SUCCESS.getCode(),allAreas.getCode()) || Objects.isNull(allAreas.getData())){
                throw new KqException(ResponseCode.ERROR_PT_AREA.getCode(),ResponseCode.ERROR_PT_AREA.getMsg());
            }
            List<TaskArea> taskAreas = new ArrayList<>(allAreas.getData().size());
            for (PtOfficeAreaDTO dto : allAreas.getData()){
                TaskArea area = new TaskArea();
                area.setAreaId(dto.getId());
                area.setName(dto.getName());
                area.setFunction(0);
                area.setParentIds(dto.getParentIds());
                area.setRegionLevel(dto.getRegionLevel());
                area.setType(String.valueOf(dto.getRegionLevel()) + 1);
                area.setCode(String.valueOf(dto.getRegionCode()) + 1);
                taskAreas.add(area);
            }
            Map<String,TaskArea> map = taskAreas.stream().collect(Collectors.toMap(TaskArea::getAreaId, Function.identity(),(k1, k2) -> k1));
            return map;
        } catch (Exception e){
            log.error("从redis中取出机构区域信息异常",e);
            ApiResponse<List<PtOfficeAreaDTO>> allAreas = govPtClient.getAllAreas();
            if(!Objects.equals(ResponseCode.SUCCESS.getCode(),allAreas.getCode()) || Objects.isNull(allAreas.getData())){
                throw new KqException(ResponseCode.ERROR_PT_AREA.getCode(),ResponseCode.ERROR_PT_AREA.getMsg());
            }
            List<TaskArea> taskAreas = new ArrayList<>(allAreas.getData().size());
            for (PtOfficeAreaDTO dto : allAreas.getData()){
                TaskArea area = new TaskArea();
                area.setAreaId(dto.getId());
                area.setName(dto.getName());
                area.setFunction(0);
                area.setParentIds(dto.getParentIds());
                area.setRegionLevel(dto.getRegionLevel());
                area.setType(String.valueOf(dto.getRegionLevel()) + 1);
                area.setCode(String.valueOf(dto.getRegionCode()) + 1);
                taskAreas.add(area);
            }
            Map<String,TaskArea> map = taskAreas.stream().collect(Collectors.toMap(TaskArea::getAreaId, Function.identity(),(k1, k2) -> k1));
            return map;
        }
    }

    public static void main(String[] args) throws IOException {
        Map<String,TaskArea> map = new HashMap<>();
        TaskArea area = new TaskArea();
        area.setName("fff");
        area.setAreaId("123456");
        area.setRegionLevel(1);
        map.put(area.getAreaId(),area);

        String str = JSON.toJSONString(map);
        System.out.println(str);

        ObjectMapper objectMapper = new ObjectMapper();
        Map<String,TaskArea> newMap = objectMapper.readValue(str,Map.class);
        System.out.println(newMap);

        System.out.println(newMap.get(area.getAreaId()));

        Map<String,TaskArea> map2 = JSONObject.parseObject(str,new TypeReference<Map<String,TaskArea>>(){});
        TaskArea ta = map2.get(area.getAreaId());
        System.out.println(ta);
        System.out.println(ta.getName());
    }

}
